package service

import (
	"fmt"
	"regexp"

	"github.com/go-playground/validator/v10"

	"forum/pkg/domain"
	"forum/pkg/model/encrypt"
)

type userService struct {
	userRepo domain.UserRepository
}

func NewUserService(userRepo domain.UserRepository) domain.UserService {
	return &userService{
		userRepo: userRepo,
	}
}

func (svc *userService) LoginAuthByPassword(Username, password string) (*domain.User, error) {
	var err error
	user := &domain.User{}

	validate := validator.New()
	err = validate.Var(Username, "email")
	if err == nil {
		user, err = svc.userRepo.GetUserByEmail(Username)
	} else {
		user, err = svc.userRepo.GetUserByName(Username)
	}
	if err != nil {
		return nil, err
	}

	if user.Password != encrypt.Md5Encrypt(password) {
		return nil, fmt.Errorf("username or password error")
	}

	return user, nil
}

func (svc *userService) CheckUser(user *domain.User) error {
	if _, err := svc.userRepo.GetUserByName(user.Name); err == nil {
		return fmt.Errorf("user name is exist ")
	}

	// validate user filed
	validate := validator.New()
	validate.RegisterValidation("name", func(fl validator.FieldLevel) bool {
		ok, _ := regexp.MatchString("^[a-zA-Z0-9_-]{4,16}$", fl.Field().String())
		return ok
	})

	validate.RegisterValidation("password", func(fl validator.FieldLevel) bool {
		ok, _ := regexp.MatchString("^[[a-zA-Z]+[0-9]*]{4,16}$", fl.Field().String())
		return ok
	})

	if err := validate.Struct(user); err != nil {
		return err
	}

	return nil
}

func (svc *userService) CreateUser(user *domain.User) error {
	// encrypt password
	user.Password = encrypt.Md5Encrypt(user.Password)

	return svc.userRepo.InsertUser(user)
}

func (svc *userService) getUserByEmailName(name, email string) (*domain.User, error) {
	// get user by name
	userByName, err := svc.userRepo.GetUserByName(name)
	if err != nil {
		return nil, err
	}

	userByEmail, err := svc.userRepo.GetUserByEmail(email)
	if err != nil {
		return nil, err
	}

	if userByName.UUID != userByEmail.UUID {
		return nil, fmt.Errorf("username or email error")
	}

	return userByName, nil
}

func (svc *userService) CheckUserFields(newUser *domain.User) (*domain.User, error) {
	user, err := svc.getUserByEmailName(newUser.Name, newUser.Email)
	if err != nil {
		return nil, fmt.Errorf("your username or email error: %v", err)
	}

	user.Password = newUser.Password
	// validate user filed
	validate := validator.New()
	validate.RegisterValidation("name", func(fl validator.FieldLevel) bool {
		ok, _ := regexp.MatchString("^[a-zA-Z0-9_-]{4,16}$", fl.Field().String())
		return ok
	})

	validate.RegisterValidation("password", func(fl validator.FieldLevel) bool {
		ok, _ := regexp.MatchString("^[a-zA-Z]+[0-9]*$", fl.Field().String())
		return ok
	})

	if err := validate.Struct(user); err != nil {
		return nil, err
	}

	return user, nil
}

func (svc *userService) GetUserByName(user *domain.User) (*domain.User, error) {
	// get user by name
	return svc.userRepo.GetUserByName(user.Name)
}

func (svc *userService) UpdateUser(user *domain.User) error {
	return svc.userRepo.UpdateUser(user)
}
